#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
@Time    : 24-5-24 下午15:37
@Author  : zhangweihao
@File    : tasks.py
'''

import datetime
import logging
from typing import List
from flask import g, session, request, send_file
from flask_restful import Resource
from model.auto_model.risk_retrieval import RiskRetrievalFile2IdModel, RiskMonitoringListModel
from ext.responses import RespHelper
from .form import *
from .serializas import *
from ext.aberrant import Error
import json
from sqlalchemy import func, and_
import pandas as pd
import asyncio
from io import BytesIO
from flask import make_response
import os
from configs.config import Configs
from uuid import uuid4
from celery_task.main import celery
from celery_task.risk_retrieval.tasks import *
from model.db_sql import DBSql
from docx import Document
from docx.shared import Pt, Inches
from docx.oxml.ns import qn
from io import StringIO

class RiskRetrievalView(Resource):

    def get(self):

        form = RiskRetrievalSearchForm().validatas_for_api()
        name = form.name.data
        all_monitor_person = g.db.session.query(RiskMonitoringListModel).filter(RiskMonitoringListModel.is_enable == 1).all()
        vip_name = [i.name for i in all_monitor_person] if all_monitor_person else []
        if name not in vip_name:
            return RespHelper.error(message=f'【{name}】不在监测范围内')
        task = workflow_asy.delay(Configs().api_key_workflow, Configs().api_key_dataset, name, vip_name)
        return RespHelper.success(message=f'开始查询【{name}】成功',data={'task_id': task.id},sorted=False)

    def post(self):
        task_id = request.json.get('task_id')
        result = celery.AsyncResult(task_id)
        if result.ready():
            document_info, res, res_origin = result.get()
            return RespHelper.success(message=f'查询成功',data={'res': res,'document_info':document_info,'status':1},sorted=False)
        return RespHelper.success(message=f'查询未完成，请稍后...',data={'res': 0,'document_info':0,'status':0},sorted=False)

class RiskRetrievalDownloadView(Resource):

    def create_docx(self, data):
        report_tempalte = os.path.join(Configs.STATIC_PATH,'report','risk_report_template.docx')
        doc = Document(report_tempalte)
        doc.styles['Normal'].font.name = u'宋体'
        doc.styles['Normal']._element.rPr.rFonts.set(qn('w:eastAsia'), u'宋体')
        doc.styles['Normal'].font.size = Pt(14)
        # doc.styles['Normal'].paragraph_format.first_line_indent = Inches(0.28) # 首行缩进

        for i in data:
            doc.add_paragraph(i)

        output = BytesIO()
        doc.save(output)
        # doc.save('./test.docx')
        output.seek(0)
        return output

    def post(self):
        task_id = request.json.get('task_id')
        result = celery.AsyncResult(task_id)
        if result.ready():
            _, _, res_origin = result.get()
            task_group = group(workflow_blocking_asy.s(Configs().api_key_report, str(res_origin), '标题'),
                                workflow_blocking_asy.s(Configs().api_key_report, str(res_origin), '内容'))()
            task_group.join()
            data = (task_group.results[0].get().replace('\n\n','\n')+task_group.results[1].get().replace('\n\n','\n')).split('\n')
            return send_file(
                    self.create_docx(data),
                    as_attachment=True,
                    attachment_filename='risk_report.docx',
                    mimetype='application/vnd.openxmlformats-officedocument.wordprocessingml.document'
                )
        return RespHelper.success(message=f'查询未完成，请稍后...',data={'res': {}},sorted=False)

class RiskAnalysisListView(Resource):
    
    def get(self):
        form = RiskAnalysisSearchForm().validatas_for_api()
        filters = []
        if form.name.data:
            filters.append(RiskMonitoringListModel.name.like(f'%{form.name.data}%'))
        if form.company.data:
            filters.append(RiskMonitoringListModel.company == form.company.data)
        if form.job.data:
            filters.append(RiskMonitoringListModel.job == form.job.data)
        if form.start_time.data and form.end_time.data:
            filters.append(RiskMonitoringListModel.update_time.between(form.start_time.data, form.end_time.data))
        
        paginat = g.db.session.query(RiskMonitoringListModel).filter(*filters).order_by(RiskMonitoringListModel.update_time.desc()).paginate()
        data = RiskAnalysisListSchema(many=True).dump(paginat.items)
        return RespHelper.success(message='查询风险分析列表成功',data={'data':data, 'pagination': paginat.page_info})

class RiskAnalysisEditView(Resource):

    def post(self):
        form = RiskAnalysisCreateForm().validatas_for_api()
        model = RiskMonitoringListModel()
        with g.db.auto_commit():
            model.name = form.name.data
            model.company = form.company.data
            model.job = form.job.data
            model.sex = form.sex.data
            model.user_id = session.get('user_id')
            g.db.session.add(model)
        # TODO 调用创建知识库任务
        asyn_create_knowledge_base.delay(form.name.data)
        return RespHelper.success(message=f'【{form.name.data}】创建成功',data={})
    
    def put(self):
        form = RiskAnalysisPutForm().validatas_for_api()
        person = RiskMonitoringListModel().get_by_id(_id=form.id.data)
        with g.db.auto_commit():
            # person.name = form.name.data
            name = person.name
            person.company = form.company.data
            person.job = form.job.data
            person.is_enable = form.is_enable.data
            if not int(person.is_enable):
                person.risk_count = 0
            person.sex = form.sex.data
            person.update_user_id = session.get('user_id')
            g.db.session.flush()

        return RespHelper.success(message=f'【{name}】编辑成功',data={})
    
    def delete(self):
        form = RiskAnalysisDeleteForm().validatas_for_api()
        ids = request.json.get('ids')
        persons = g.db.session.query(RiskMonitoringListModel).filter(RiskMonitoringListModel.id.in_(ids)).all()
        person_name_list = []
        if persons:
            for person in persons:
                person_name_list.append(person.name)
                # TODO 删除所有被删除人所拥有的知识库
                asyn_delete_knowledge_base.delay(person.name)
                with g.db.auto_commit():
                    g.db.session.delete(person)
        person_name_list = set(person_name_list)
        return RespHelper.success(message=f'【{".".join(person_name_list)}】删除成功',data={})

class RiskAnalysisBubbleView(Resource):
    def get(self):
        form = RiskAnalysisBubbleForm().validatas_for_api()
        filters = [RiskMonitoringListModel.is_enable == 1]
        if form.start_time.data and form.end_time.data:
            filters.append(RiskMonitoringListModel.update_time.between(form.start_time.data, form.end_time.data))
        
        all_data = g.db.session.query(RiskMonitoringListModel).filter(*filters). \
            order_by(RiskMonitoringListModel.risk_count.desc()).limit(int(form.top.data)).all()
        data = RiskAnalysisListSchema(many=True).dump(all_data)
        return RespHelper.success(message='查询风险分析气泡图成功',data={'data':data})

class RiskAnalysisImportView(Resource):
    def validate_data(self, df:pd.DataFrame, error_list:list, column_name:str):
        def check(x):
            if x and (len(x) < 2 or len(x) > 64):
                return True
            return False
        df[column_name] = df[column_name].map(lambda x: str(x))
        name_error_index_list2 = df[df[column_name].apply(lambda x: check(x))].index.tolist()
        name_error_index_list2 = [x + 1 for x in name_error_index_list2]
        name_error_index_list2 = list(map(str, name_error_index_list2))
        column_dict = {
            'name': '姓名',
            'company': '公司名称',
            'job': '职务名称',
        }
        if name_error_index_list2:
            error_list.append(f'{column_dict.get(column_name)}长度不合法，'
                              f'第{"," .join(name_error_index_list2)}条数据{column_dict.get(column_name)}长度不合法')

    def validate_name(self, df:pd.DataFrame, error_list:list):
        name_error_index_list = df[df['name'].isna()].index.values.tolist()
        name_error_index_list = [x + 1 for x in name_error_index_list]
        name_error_index_list = list(map(str, name_error_index_list))
        if name_error_index_list:
            error_list.append(f'姓名必填，第{"," .join(name_error_index_list)}条数据姓名有误')

    def validate_sex(self, df:pd.DataFrame, error_list:list):
        sex_error_index_list = df[(df['sex'] != 0) & (df['sex'] != 1)].index.values.tolist()
        sex_error_index_list = [x + 1 for x in sex_error_index_list]
        sex_error_index_list = list(map(str, sex_error_index_list))
        if sex_error_index_list:
            error_list.append(f'第{"," .join(sex_error_index_list)}条数据性别有误')
    
    def post(self):
        if 'file' not in request.files:
            return RespHelper.error(message='请上传文件')
        file = request.files['file']
        try:
            file_content = file.stream.read().decode()
        except:
            return RespHelper.error(message=f'批量导入失败，请将文件保存为UTF-8编码的csv文件')
        file_object = StringIO(file_content)
        df = pd.read_csv(file_object,skiprows=1,names=['name', 'company', 'job', 'sex'])
        if df.empty:
            return RespHelper.error(message='批量导入失败,数据为空',data={'error_msg':['数据为空']})
        if df.shape[1] != 4:
            return RespHelper.error(message='批量导入失败,文件格式有误',data={'error_msg':['文件格式有误']})
        df['sex'] = df['sex'].fillna('男')
        df['company'] = df['company'].fillna('')
        df['job'] = df['job'].fillna('')
        df['sex'] = df['sex'].replace({'男': 0, '女': 1})
        error_list = []
        self.validate_data(df,error_list,'name')
        self.validate_data(df,error_list,'company')
        self.validate_data(df,error_list,'job')
        self.validate_name(df,error_list)
        self.validate_sex(df,error_list)
        
        if error_list:
            return RespHelper.error(message=f'批量导入失败。{";".join(error_list)}',data={'error_msg':error_list})
        add_model_list = []
        add_list = df.values.tolist()
        user_id = session.get('user_id')
        with g.db.auto_commit():
            for item in add_list:
                model = RiskMonitoringListModel()
                model.name = item[0]
                model.company = item[1]
                model.job = item[2]
                model.sex = item[3]
                model.user_id = user_id
                model.update_user_id = user_id
                add_model_list.append(model)
            g.db.session.add_all(add_model_list)
        return RespHelper.success(message='批量导入成功')
        
        
